﻿using System;
using System.Collections.Generic;

namespace BullsAndCows
{
    class BullsAndCows
    {
        const int NUMBERSIZE = 4;
        static int[] numberToGuess = new int[NUMBERSIZE];
        static bool[] cheatsUsed = new bool[NUMBERSIZE];
        static int cheats = 0;
        static int attempts = 0;
        static SortedDictionary<int, string> scoreBoard = new SortedDictionary<int, string>();
        
        public static int[] NumberToGuess
        {
            get
            {
                return numberToGuess;
            }
            set
            {
                numberToGuess = value;
            }
        }

        public static bool[] CheatsUsed
        {
            get
            {
                return cheatsUsed;
            }
        }

        public static int Cheats
        {
            get
            {
                return cheats;
            }
        }

        public static int Attempts
        {
            get
            {
                return attempts;
            }
        }

        public static SortedDictionary<int, string> ScoreBoard
        {
            get
            {
                return scoreBoard;
            }
        }

        static void Main()
        {
            StartNewGame();
            string input = "";
            bool won = false;
            do
            {
                Console.Write("Enter your guess or command: ");
                input = Console.ReadLine();
                ProcessCommand(input, ref won);
                if (won && (cheats == 0))
                {
                    AddToScoreBoard();
                    cheats ++;
                }
            }
            while (input != "exit");
            Console.WriteLine("Good Bye!");
        }
  
        private static void ProcessCommand(string input, ref bool won)
        {
            switch (input)
            {
                case "top":
                    PrintTop();
                    break;
                case "restart":
                    StartNewGame();
                    won = false;
                    break;
                case "help":
                    if (won)
                    {
                        Console.WriteLine("You have already won!");
                        break;
                    }
                    Cheat();
                    break;
                case "exit":
                    break;
                default:
                    int guess;
                    if (int.TryParse(input, out guess) && (!won))
                    {
                        won = CheckForCowsAndBulls(guess);
                    }
                    else
                    {
                        Console.WriteLine("Incorrect guess or command!");
                    }
                    break;
            }
        }
  
        private static void AddToScoreBoard()
        {
            if (!scoreBoard.ContainsKey(attempts))
            {
                Console.WriteLine("Enter your name for the coreboard: ");
                string input = Console.ReadLine();
                string result = input + "------>" + attempts;
                scoreBoard.Add(attempts, result);
            }
        }

        private static bool CheckForCowsAndBulls(int guess)
        {
            attempts++;
            int[] guessedArray = new int[NUMBERSIZE];
            int bulls = 0;
            int cows = 0;
            for (int i = 0; i < NUMBERSIZE; i++)
            {
                guessedArray[NUMBERSIZE - 1 - i] = guess % 10;
                guess /= 10;
            }
            for (int i = 0; i < NUMBERSIZE; i++)
            {
                if (guessedArray[i] == numberToGuess[i])
                {
                    bulls++;
                }
                else
                {
                    for (int j = 0; j < NUMBERSIZE; j++)
                    {
                        if (guessedArray[i] == numberToGuess[(i + j) % NUMBERSIZE])
                        {
                            cows++;
                        }
                    }
                }
            }
            if (bulls == 4)
            {
                Console.WriteLine("Congratulations! You guessed the secret number in {0} attempts and {1} cheats.", attempts , cheats);
                return true;
            }
            Console.WriteLine("Wrong number! Bulls: {0}, Cows: {1}", bulls, cows);
            return false;
        }

        private static void Cheat()
        {
            cheats++;
            Random rand = new Random();
            int position = rand.Next(0, NUMBERSIZE);
            for (int i = 0; i < NUMBERSIZE; i++)
            {
                if (!cheatsUsed[(position + i) % NUMBERSIZE])
                {
                    cheatsUsed[(position + i) % NUMBERSIZE] = true;
                    for (int j = 0; j < NUMBERSIZE; j++)
                    {
                        if (cheatsUsed[j])
                        {
                            Console.Write(numberToGuess[j]);
                        }
                        else
                        {
                            Console.Write("X");
                        }
                    }
                    Console.WriteLine();
                    return;
                }
            }
            Console.WriteLine("You have no more cheats left!");
        }

        private static void StartNewGame()
        {
            HashSet<int> existing = new HashSet<int>();
            Random rand = new Random();
            for (int i = 0; i < NUMBERSIZE; i++)
            {
                int newNumber;
                do
                {
                    newNumber = rand.Next(0, 10);
                }
                while(existing.Contains(newNumber));

                numberToGuess[i] = newNumber;
                existing.Add(numberToGuess[i]);
            }
            for (int i = 0; i < NUMBERSIZE; i++)
            {
                cheatsUsed[i] = false;
            }
            attempts = 0;
            cheats = 0;

            Console.WriteLine("Welcome to “Bulls and Cows” game. Please try to guess my secret 4-digit number." +
                              "Use 'top' to view the top scoreboard, 'restart' to start a new game and 'help' to cheat and 'exit'" +
                              " to quit the game.");
        }

        private static void PrintTop()
        {
            int count = 0;
            foreach (var item in scoreBoard)
            {
                count++;
                Console.WriteLine(item.Value);
                if (count == 5)
                {
                    break;
                }
            }
        }
    }
}